package com.linksoul.filter;

import com.linksoul.utils.RequestIdHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 请求ID拦截器，主要功能：
 * 1. 检查请求头是否包含X-Request-Id
 * 2. 如果没有则生成UUID作为请求ID
 * 3. 将请求ID存入ThreadLocal供整个请求生命周期使用
 * 4. 将请求ID添加到响应头中
 * 5. 提供详细的日志输出用于调试
 * 6. 确保请求完成后清理ThreadLocal防止内存泄漏
 */
public class RequestIdInterceptor implements HandlerInterceptor {
    // 日志记录器
    private static final Logger logger = LoggerFactory.getLogger(RequestIdInterceptor.class);

    // 请求ID在HTTP头中的字段名
    private static final String REQUEST_ID_HEADER = "X-Request-Id";

    /**
     * 请求处理前执行的方法
     * @param request HTTP请求对象
     * @param response HTTP响应对象
     * @param handler 目标处理器
     * @return 是否继续处理请求（true继续，false终止）
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 从请求头获取请求ID
        String incomingRequestId = request.getHeader(REQUEST_ID_HEADER);

        if (incomingRequestId == null || incomingRequestId.isEmpty()) {
            // 如果请求头中没有请求ID，则生成一个新的UUID
            String generatedRequestId = UUID.randomUUID().toString();
            RequestIdHolder.set(generatedRequestId);

            // 记录调试日志：生成的请求ID、请求方法和URI
            logger.debug("生成新的请求ID: {} 请求: {} {}",
                    generatedRequestId,
                    request.getMethod(),
                    request.getRequestURI());

            // 如果启用了TRACE级别日志，记录所有请求头信息
            if (logger.isTraceEnabled()) {
                logger.trace("请求头详细信息 - {} {}: {}",
                        request.getMethod(),
                        request.getRequestURI(),
                        getHeadersAsString(request));
            }
        } else {
            // 如果请求头中已有请求ID，则使用该ID
            RequestIdHolder.set(incomingRequestId);
            logger.debug("使用客户端提供的请求ID: {} 请求: {} {}",
                    incomingRequestId,
                    request.getMethod(),
                    request.getRequestURI());
        }

        // 将请求ID添加到响应头中，方便前端调试
        response.setHeader(REQUEST_ID_HEADER, RequestIdHolder.get());

        return true;
    }

    /**
     * 请求完成后执行的方法（视图渲染完成后）
     * @param request HTTP请求对象
     * @param response HTTP响应对象
     * @param handler 目标处理器
     * @param ex 处理过程中抛出的异常（如果有）
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 记录请求完成日志
        logger.debug("请求处理完成，请求ID: {}", RequestIdHolder.get());
        // 必须清除ThreadLocal，防止内存泄漏
        RequestIdHolder.remove();
    }

    /**
     * 辅助方法：将请求头转换为格式化字符串
     * @param request HTTP请求对象
     * @return 格式为"头名称: 头值; ..."的字符串
     */
    private String getHeadersAsString(HttpServletRequest request) {
        StringBuilder headers = new StringBuilder();
        // 获取所有请求头名称的枚举
        Enumeration<String> headerNames = request.getHeaderNames();

        // 遍历所有请求头
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            // 拼接头名称和值
            headers.append(headerName)
                    .append(": ")
                    .append(request.getHeader(headerName))
                    .append("; ");
        }

        return headers.toString();
    }
}